/*
 * tictac.c
 *
 *  Created on: 2016年8月29日
 *      Author: LongShu
 */

#include "tictac.h"

//#define _DEBUG
long findbestmove = 0;
long evaluateposition = 0;

int main(int argc, char **argv) {
	stateT state;
	moveT move;
	GiveInstructions();
	state = NewGame();
	while (!GameIsOver(state)) {
		findbestmove = 0;
		evaluateposition = 0;
		DisplayGame(state);
		switch (WhoseTurn(state)) {
		case Human:
			move = GetUserMove(state);
			break;
		case Computer:
			move = ChooseComputerMove(state);
			DisplayMove(move);
			break;
		}
		MakeMove(state, move);
	}
	AnnounceResult(state);
	return 0;
}

/*
 * 核心
 */
static moveT FindBestMove(stateT state, int depth, int *pRating) {
	findbestmove++;
	moveT moveArray[MaxMoves], move, bestMove = 20;
	int i, nMoves, rating, minRating;
	nMoves = GenerateMoveList(state, moveArray);
	if (nMoves == 0)
		Error("Np moves available");
	minRating = WinningPosition + 1;
	for (i = 0; i < nMoves && minRating != LosingPosition; i++) {
		move = moveArray[i];
		MakeMove(state, move);
		//选择最优
		rating = EvaluatePosition(state, depth + 1);
		if (rating < minRating) {
			bestMove = move;
			minRating = rating;
		}
		RetractMove(state, move);
	}
	*pRating = -minRating;
#ifdef _DEBUG
	println(bestMove=%d, bestMove);
#endif
	return (bestMove);
}

static int EvaluatePosition(stateT state, int depth) {
	evaluateposition++;
	int rating;
	if (GameIsOver(state) || depth >= MaxDepth) {
		return (EvaluateStaticPosition(state));
	}
	(void) FindBestMove(state, depth, &rating);
	return (rating);
}

static stateT NewGame(void) {
	stateT state;
	int i = 0;
	state = New(stateT);
	for (i = 0; i <= 9; i++) {
		state->board[i] = ' ';
	}
	state->whoseTurn = FirstPlayer;
	state->turnsTaken = 0;
	return (state);
}

static void DisplayGame(stateT state) {
	int row, col;
	if (GameIsOver(state)) {
		println(\n[The final position looks like this:]);
	} else {
		println(\n[The game now looks like this:]);
	}
	for (row = 0; row < 3; row++) {
		if (row != 0)
			println(----+----+----);
		for (col = 0; col < 3; col++) {
			if (col != 0)
				print(|);
			print(%-4c, state->board[row * 3 + col + 1]);
		}
		println();
	}
	println();
}

static void DisplayMove(moveT move) {
	println("I'll move to square %d.", move);
}

static void GiveInstructions(void) {
	println("Welcome to tic-tac-toe.The object of the game.");
	println(
			"Is to line up three symbols in a row,vertically,horizontally,or diagonally.");
	println("You'll be %c and ", PlayerMark(Human));
	println("I'll be %c.", PlayerMark(Computer));
}

static char PlayerMark(playerT player) {
	if (player == FirstPlayer) {
		return ('X');
	} else {
		return ('O');
	}
}

static moveT GetUserMove(stateT state) {
	moveT move;
	println(Your move.);
	while (TRUE) {
		print(what square?);
		move = GetInteger();
		if (MoveIsLegal(move, state))
			break;
		println(That move is illegal. Try again.);
	}
	return (move);
}

static bool MoveIsLegal(moveT move, stateT state) {
	return (move >= 1 && move <= 9 && state->board[move] == ' ');
}

static moveT ChooseComputerMove(stateT state) {
	int rating;
	println("My move.");
	return (FindBestMove(state, 0, &rating));
}

static int GenerateMoveList(stateT state, moveT moveArray[]) {
	int i, nMoves;
	nMoves = 0;
	for (i = 1; i <= 9; i++) {
		if (state->board[i] == ' ') {
			moveArray[nMoves++] = (moveT) i;
		}
	}
	return (nMoves);
}

static void MakeMove(stateT state, moveT move) {
	state->board[move] = PlayerMark(state->whoseTurn);
	state->whoseTurn = Opponent(state->whoseTurn);
	state->turnsTaken++;
}

static bool GameIsOver(stateT state) {
	return (state->turnsTaken == 9 || CheckForWin(state, state->whoseTurn)
			|| CheckForWin(state, Opponent(state->whoseTurn)));
}

static void RetractMove(stateT state, moveT move) {
	state->board[move] = ' ';
	state->whoseTurn = Opponent(state->whoseTurn);
	state->turnsTaken--;
}

static void AnnounceResult(stateT state) {
	DisplayGame(state);
	if (CheckForWin(state, Human)) {
		println("你赢了!");
	} else if (CheckForWin(state, Computer)) {
		println("我赢了!");
	} else {
		println("Cat's game!");
	}
}

static int EvaluateStaticPosition(stateT state) {
	if (CheckForWin(state, state->whoseTurn)) {
		return (WinningPosition);
	}
	if (CheckForWin(state, Opponent(state->whoseTurn))) {
		return (LosingPosition);
	}
	return (NeutralPosition);
}

static bool CheckForWin(stateT state, playerT player) {
	char mark;
	if (state->turnsTaken < 5)
		return (FALSE);
	mark = PlayerMark(player);
	for (int i = 0; i < nWinningLines; i++) {
		if (mark == state->board[winningLines[i][0]]
				&& mark == state->board[winningLines[i][1]]
				&& mark == state->board[winningLines[i][2]]) {
			return (TRUE);
		}
	}
	return (FALSE);
}

static playerT WhoseTurn(stateT state) {
	return (state->whoseTurn);
}

/*
 * 玩家切换
 */
static playerT Opponent(playerT player) {
	switch (player) {
	case Human:
		return (Computer);
	case Computer:
		return (Human);
	default:
		return (Human);
	}
}
